/**
* Copyright @ 2023 iAuto (Shanghai) Co., Ltd.
* All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are NOT permitted except as agreed by
* iAuto (Shanghai) Co., Ltd.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*/



const categorySeparator = '<sep gap="36"/>';

const blockSeparator = '<sep gap="36"/>'; // At default scale, about 28px

/* eslint-disable no-unused-vars */
const xmlEscape = function (unsafe) {
  return unsafe.replace(/[<>&'"]/g, (c) => {
    switch (c) {
      case '<':
        return '&lt;';
      case '>':
        return '&gt;';
      case '&':
        return '&amp;';
      case "'":
        return '&apos;';
      case '"':
        return '&quot;';
    }
  });
};
 // eslint-disable-next-line
const control = function (isInitialSetup, isStage) {
  return `
    <category name="%{BKY_CATEGORY_CONTROL}" id="control" iconURI="">
        <block type="control_if"/>
        <block type="control_if_else"/>
        ${blockSeparator}

        <block type="control_loop">
            <value name="TIMES">
                <shadow type="control_loop_times" />
            </value>
        </block>
        ${blockSeparator}
        <block type="operator_and"/>
        <block type="operator_or"/>
        ${blockSeparator}
        <block type="control_exit"/>
    </category>
    `;
};

/* eslint-enable no-unused-vars */

const xmlOpen = '<xml style="display: none">';
const xmlClose = '</xml>';

/**
 * @param {!boolean} isInitialSetup - Whether the toolbox is for initial setup. If the mode is "initial setup",
 * blocks with localized default parameters (e.g. ask and wait) should not be loaded. (LLK/scratch-gui#5445)
 * @param {?boolean} isStage - Whether the toolbox is for a stage-type target. This is always set to true
 * when isInitialSetup is true.
 * @param {?string} targetId - The current editing target
 * @param {?Array.<object>} categoriesXML - optional array of `{id,xml}` for categories. This can include both core
 * and other extensions: core extensions will be placed in the normal Scratch order; others will go at the bottom.
 * @property {string} id - the extension / category ID.
 * @property {string} xml - the `<category>...</category>` XML for this extension / category.
 * @param {?string} costumeName - The name of the default selected costume dropdown.
 * @param {?string} backdropName - The name of the default selected backdrop dropdown.
 * @param {?string} soundName -  The name of the default selected sound dropdown.
 * @returns {string} - a ScratchBlocks-style XML document for the contents of the toolbox.
 */
const makeToolboxXML = function (
  isInitialSetup,
  isStage = true,
  targetId,
  categoriesXML = [],
  costumeName = '',
  backdropName = '',
  soundName = '',
) {
  isStage = isInitialSetup || isStage;
  const gap = [categorySeparator];
 // eslint-disable-next-line
  costumeName = xmlEscape(costumeName);
   // eslint-disable-next-line
  backdropName = xmlEscape(backdropName);
   // eslint-disable-next-line
  soundName = xmlEscape(soundName);

  categoriesXML = categoriesXML.slice();
  const moveCategory = (categoryId) => {
    const index = categoriesXML.findIndex((categoryInfo) => categoryInfo.id === categoryId);
    if (index >= 0) {
      // remove the category from categoriesXML and return its XML
      const [categoryInfo] = categoriesXML.splice(index, 1);
      return categoryInfo.xml;
    }
    // return `undefined`
  };

  const controlXML = moveCategory('control') || control(isInitialSetup, isStage, targetId);

  const everything = [xmlOpen, controlXML, gap,];

  for (const extensionCategory of categoriesXML) {
    everything.push(gap, extensionCategory.xml);
  }

  everything.push(xmlClose);
  return everything.join('\n');
};

export default makeToolboxXML;
